package com.runwalk.video.blobs;

//==================================================
//class Metaballs2D
//==================================================
public class Metaballs2D
{
	// Isovalue
	// ------------------
	protected float isovalue;

	// Grid
	// ------------------
	protected int  resx,resy;
	protected float stepx,stepy;
	protected float[] gridValue;
	protected int nbGridValue;  

	// Voxels      
	// ------------------
	protected int[] voxel;
	protected int nbVoxel;

	// EdgeVertex
	// ------------------
	protected EdgeVertex[] edgeVrt;
	protected int nbEdgeVrt;  

	// Lines
	// what we pass to the renderer
	// ------------------
	protected int[] lineToDraw;  
	protected int nbLineToDraw;

	// Constructor
	// ------------------
	public Metaballs2D(){}


	// init(int, int)
	// ------------------
	public void init(int resx, int resy)
	{
		this.resx = resx;
		this.resy = resy;

		this.stepx = 1.0f/( (float)(resx-1));
		this.stepy = 1.0f/( (float)(resy-1));

		// Allocate gridValue
		nbGridValue	= resx*resy;
		gridValue	= new float[nbGridValue];

		// Allocate voxels
		nbVoxel		= nbGridValue;
		voxel		= new int[nbVoxel];

		// Allocate EdgeVertices
		edgeVrt 	= new EdgeVertex [2*nbVoxel];
		nbEdgeVrt 	= 2*nbVoxel;

		// Allocate Lines
		lineToDraw 		= new int[2*nbVoxel];
		nbLineToDraw 	= 0;

		// Precompute some values
		int x,y,n,index;
		n = 0;
		for (x=0 ; x<resx ; x++)
			for (y=0 ; y<resy ; y++)
			{
				index = 2*n;
				// index to edgeVrt
				voxel[x+resx*y] = index;
				// values
				edgeVrt[index]   = new EdgeVertex(x*stepx, y*stepy);
				edgeVrt[index+1] = new EdgeVertex(x*stepx, y*stepy);

				// Next!
				n++;
			}

	}

	// computeIsovalue()
	// ------------------
	public void computeIsovalue()
	{

		// A simple test : put a metaball on center of the screen
		/*
	float	ballx = 0.5f;
	float	bally = 0.5f;
	float	vx,vy;
	float	dist;

	int x,y;
	vx = 0.0f;
	for (x=0 ; x<resx; x++)
	{	
		vy = 0.0f;
		for (y=0 ; y<resy; y++)
		{
			dist = (float)sqrt((vx-ballx)*(vx-ballx) + (vy-bally)*(vy-bally));
			gridValue[x+resx*y] = 10.0f/(dist*dist+0.001f);
			vy+=stepy;
		}
		vx+=stepx;
	}
		 */


	}


	// computeMesh()
	// ------------------
	public void computeMesh()
	{
		// Compute IsoValue
		computeIsovalue();
		// Get Lines indices

		int					x,y,squareIndex,n;
		int					iEdge;
		int					offx, offy, offAB;
		int					toCompute;
		int					offset;
		float					t;
		float					vx,vy;
		int[]                                   edgeOffsetInfo;

		nbLineToDraw = 0;
		vx	     = 0.0f;
		for (x=0 ; x<resx-1 ; x++)
		{
			vy = 0.0f;
			for (y=0 ; y<resy-1 ; y++)
			{
				offset		= x + resx*y;
				squareIndex = getSquareIndex(x,y);

				n	        = 0;
				while ( (iEdge = MetaballsTable.edgeCut[squareIndex][n++]) != -1)
				{
					edgeOffsetInfo          = MetaballsTable.edgeOffsetInfo[iEdge];
					offx			= edgeOffsetInfo[0];
					offy			= edgeOffsetInfo[1];
					offAB			= edgeOffsetInfo[2];

					lineToDraw[nbLineToDraw++] = voxel[(x+offx) + resx*(y+offy)] + offAB;
				}

				toCompute = MetaballsTable.edgeToCompute[squareIndex];
				if (toCompute>0)
				{
					if ( (toCompute & 1) > 0) // Edge 0
					{
						t	= (isovalue - gridValue[offset]) / (gridValue[offset+1] - gridValue[offset]); 
						edgeVrt[voxel[offset]].x = vx*(1.0f-t) + t*(vx+stepx);
					}
					if ( (toCompute & 2) > 0) // Edge 3
					{
						t	= (isovalue - gridValue[offset]) / (gridValue[offset+resx] - gridValue[offset]); 
						edgeVrt[voxel[offset]+1].y = vy*(1.0f-t) + t*(vy+stepy);
					}

				} // toCompute
				vy += stepy;
			}	// for y

			vx += stepx;
		}	// for x

		nbLineToDraw /= 2;

	}

	// getSquareIndex(int,int)
	// ------------------
	protected int getSquareIndex(int x, int y)
	{
		int squareIndex = 0;
		int offy  = resx*y;
		int offy1 = resx*(y+1);
		if (gridValue[x+offy]		< isovalue) squareIndex |= 1;
		if (gridValue[x+1+offy]		< isovalue) squareIndex |= 2;
		if (gridValue[x+1+offy1]	< isovalue) squareIndex |= 4;
		if (gridValue[x+offy1]		< isovalue) squareIndex |= 8;
		return squareIndex;
	}

	// setIsoValue(float)
	// ------------------
	public void setIsovalue(float iso){this.isovalue = iso;}



}